今天的內容會著重在 Flutter 的效能議題
其中會分成四個類型
在 APP 繪製動畫時,最常被提及的主題便是如何測量效能。
有著 Skia 引擎高速繪製及丟棄 Widgets 的特性,在絕大多數狀況下 Flutter 皆是具備足夠繪製效能的
因此只要避開常見的陷阱便能達到很好的效能
當見到不順暢的動畫出現時,我們必須確保是否有使用 Debug 模式
由於在 Debug 模式下不會使用 Release 的模式執行
在效能上還不到生產環境下的速度
因此在確定效能瓶頸前先檢查是否用的是 Debug 模式或是 Profile 模式!
而以下要提及的是常見的效能瓶頸的狀況
而以下則是通用的心法及技巧讓我們可以不寫出效率差的程式碼
某些操作會相較其他的操作更加耗費時間
因此選擇在適當的狀況下選擇好的操作
可以有效提高運算效能
在設計 UI 時,有些東西必須記於心中!
build()
函式中,由於 build()
會在上層 Widgetbuild()
函式中建構大型的單一 Widget,當這樣的狀況發生時,便應該思考將其拆setState()
被呼叫時,底下的 Widget 也需要跟著重建,setState()
只為了小部分的 Widget 樹變化而 Flutter 在遍歷 Widget 樹時,如果該 Widget 與先前繪製的 Widget 相同的情況下
則不會進行重繪,也因此可以優化效能。
而如果可以的話,盡量使用 const constructors 在 Widget 上
它能夠使得 Flutter 停止大多重繪製的作業
而在共享的 UI 上盡量使用 StatelessWidget
來取代函式建置的方式
詳細可參閱
Performance considerations
Widgets vs helper methods
saveLayer
在某些 Flutter 程式碼會在實作 UI 視覺效果時用到 saveLayer()
然而這個操作是非常花費時間的!
而就算我們本身撰寫的程式碼沒用到,但仍有可能在使用到的 Widget 及套件中使用到該函式
如果在沒有控管好的狀況下胡亂使用的話,就可能會導致 jank 的發生
!jank : 畫面卡幀
呼叫 saveLayer()
會要求一個不在畫面上呈現的緩衝區空間並將內容繪製在上面
而此時 GPU 會像是水管般的運作,Render switch 將強制 GPU 重新導入暫時的 stream 並且將其送回去
而在手機 GPU 中,這項操作會特別影響渲染的性能。
saveLayer
呢?如果我們需要動態顯示大量的圖形,我們假設這些圖形皆來源自 Server
而這些圖形有些透明度並且可能相疊也可能不相疊
則此時我們便可能需要使用到 saveLayer()
saveLayer
情況發生時,如何 Debug ?我們可以透過 DevTools 的時間線來偵測是否有直接或間接的呼叫 saveLayer()
可以開啟 DevTools 的 PerformanceOverlayLayer.checkerboardOffscreenLayers
來查看狀態
而這個按鈕在 Performance View 可以看得到
saveLayer
如何避免呼叫 saveLayer 呢?
如果是來自我們程式碼的呼叫,或許我們能降低甚至不使用它們?
舉個例子,或許我們的 UI 重疊了兩個圖形,每個圖形皆擁有非零的透明度:
1. 如果他們總是同時出現,則我們可以透過預先計算以及快取等機制來避免呼叫 saveLayer
當我們可以預先計算時,便可以避免 saveLayer 的使用了
2. 又或者我們可以重構我們的程式邏輯來避免兩個圖片重疊在一起?
那如果是來自套件的呼叫的話,或許聯繫套件擁有者並討論為何這些呼叫是必須的?
是否有方式是可以降低或甚至不使用它們的?
如果沒辦法的話或許可以找尋其他套件或甚至是自己撰寫相同功能的套件來避免使用
而以下這些 Widget 也有可能會呼叫到 saveLayer
官網內文還有提及很多需要注意的地方
因為時間的關係或許不能一一介紹完畢
剩下的之後會找時間補上
也歡迎讀者閱讀後一起討論 ~